// Copyright 2022 a.o.smith ALL Rights Reserved
package com.liuxinlong.modules.chimi.service.impl;

import com.alibaba.fastjson.JSON;
import com.liuxinlong.common.AosException;
import com.liuxinlong.common.SnowFlake;
import com.liuxinlong.constant.ThreadLocalConstants;
import com.liuxinlong.constant.TimeFormatConstants;
import com.liuxinlong.enums.ReturnCodes;
import com.liuxinlong.modules.chimi.service.BarPointsRuleService;
import com.liuxinlong.modules.dao.BarPointsRuleDao;
import com.liuxinlong.modules.dao.BarPointsRuleDetailDao;
import com.liuxinlong.modules.entity.BarPointsRule;
import com.liuxinlong.modules.entity.BarPointsRuleDetail;
import com.liuxinlong.modules.entity.User;
import com.liuxinlong.utils.ObjectUtils;
import com.liuxinlong.utils.RedisUtils;
import com.liuxinlong.utils.ThreadlocalUtils;
import com.liuxinlong.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 论坛积分规则服务层接口实现
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2023-06-14
 */
@Service
@Slf4j
public class BarPointsRuleServiceImpl implements BarPointsRuleService {

    @Autowired
    private BarPointsRuleDao barPointsRuleDao;

    @Autowired
    private BarPointsRuleDetailDao barPointsRuleDetailDao;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public List<Map<String, Object>> pagePointsRule(Map<String, Object> queryParam) {
        int startNum = (int) queryParam.get("startNum");
        List<BarPointsRule> originalList = barPointsRuleDao.pageBarPointsRule(queryParam);
        return completeResult(originalList, startNum);
    }

    @Override
    public int getPointsRuleCount(Map<String, Object> queryParam) {
        return barPointsRuleDao.getBarPointsRuleCount(queryParam);
    }

    @Override
    public void addPointsRule(BarPointsRule barPointsRule) {
        barPointsRule.setId(SnowFlake.nextIdStr());
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        barPointsRule.setCreateTime(currentTime);
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        barPointsRule.setCreateUser(currentUser.getId());
        barPointsRuleDao.insert(barPointsRule);
    }

    @Override
    public void updatePointsRule(BarPointsRule barPointsRule) {
        String id = barPointsRule.getId();
        if (StringUtils.isEmpty(id)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分规则信息异常，规则不存在！");
        }
        BarPointsRule oldInfo = barPointsRuleDao.selectById(id);
        if (ObjectUtils.isEmpty(oldInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分规则信息异常，规则不存在！");
        }
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        oldInfo.setUpdateTime(currentTime);
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        oldInfo.setUpdateUser(currentUser.getId());
        barPointsRuleDao.updateById(barPointsRule);
    }

    @Override
    public void deletePointsRule(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "删除积分规则信息异常，规则不存在！");
        }
        BarPointsRule oldInfo = barPointsRuleDao.selectById(id);
        if (ObjectUtils.isEmpty(oldInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "删除积分规则信息异常，规则不存在！");
        }
        barPointsRuleDao.deleteById(id);
    }

    @Override
    public void updatePointsRuleStatus(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分规则信息异常，规则不存在！");
        }
        BarPointsRule oldInfo = barPointsRuleDao.selectById(id);
        if (ObjectUtils.isEmpty(oldInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分规则信息异常，规则不存在！");
        }
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("ruleId", id);
        queryParam.put("startNum", 0);
        queryParam.put("pageSize", 100);
        List<BarPointsRuleDetail> detailList = barPointsRuleDetailDao.pageBarPointsRuleDetail(queryParam);
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        if (oldInfo.getStatus() == 0) {
            if (detailList.isEmpty()) {
                throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "积分规则不包含可用规则，启用失败！");
            }
            Map<String, Object> queryRuleParam = new HashMap<>();
            queryRuleParam.put("startTime", oldInfo.getStartTime());
            queryRuleParam.put("endTime", oldInfo.getEndTime());
            int effectiveNum = barPointsRuleDao.getEffectiveRuleCount(queryRuleParam);
            if (effectiveNum > 0) {
                throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "积分规则生效区间内已存在生效规则，启用失败！");
            }
            if (TimeUtils.compareDate(currentTime, oldInfo.getStartTime(), TimeFormatConstants.YYYY_MM_DD_HH_MM_SS) > 0 &&
                    TimeUtils.compareDate(currentTime, oldInfo.getEndTime(), TimeFormatConstants.YYYY_MM_DD_HH_MM_SS) < 0) {
                Map<String, Object> ruleDataMap = new HashMap<>();
                for (BarPointsRuleDetail detail : detailList) {
                    ruleDataMap.put(String.valueOf(detail.getSourceType()), JSON.toJSON(detail).toString());
                }
                redisUtils.setPointsRulesCache(ruleDataMap);
            }
        } else {
            if (TimeUtils.compareDate(currentTime, oldInfo.getStartTime(), TimeFormatConstants.YYYY_MM_DD_HH_MM_SS) > 0 &&
                    TimeUtils.compareDate(currentTime, oldInfo.getEndTime(), TimeFormatConstants.YYYY_MM_DD_HH_MM_SS) < 0) {
                Map<String, Object> ruleDataMap = new HashMap<>();
                redisUtils.setPointsRulesCache(ruleDataMap);
            }
        }
        oldInfo.setStatus(oldInfo.getStatus() == 0 ? 1 : 0);
        oldInfo.setUpdateTime(currentTime);
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        oldInfo.setUpdateUser(currentUser.getId());
        barPointsRuleDao.updateById(oldInfo);
    }

    @Override
    public List<Map<String, Object>> pagePointsRuleDetail(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "查询积分规则信息异常，规则不存在！");
        }
        BarPointsRule ruleInfo = barPointsRuleDao.selectById(id);
        if (ObjectUtils.isEmpty(ruleInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "查询积分规则信息异常，规则不存在！");
        }
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("ruleId", id);
        queryParam.put("startNum", 0);
        queryParam.put("pageSize", 100);
        List<BarPointsRuleDetail> detailList = barPointsRuleDetailDao.pageBarPointsRuleDetail(queryParam);
        List<Map<String, Object>> dataList = new ArrayList<>(detailList.size());
        for (BarPointsRuleDetail detail : detailList) {
            Map<String, Object> item = ObjectUtils.object2Map(detail);
            dataList.add(item);
        }
        return dataList;
    }

    @Override
    public void updatePointsRuleDetail(String id, List<BarPointsRuleDetail> detailList) {
        if (StringUtils.isEmpty(id)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分规则信息异常，规则不存在！");
        }
        BarPointsRule ruleInfo = barPointsRuleDao.selectById(id);
        if (ObjectUtils.isEmpty(ruleInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分规则信息异常，规则不存在！");
        }
        if (ruleInfo.getStatus() == 1) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分规则信息异常，规则已生效！");
        }
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("ruleId", id);
        queryParam.put("startNum", 0);
        queryParam.put("pageSize", 100);
        List<BarPointsRuleDetail> oldDetailList = barPointsRuleDetailDao.pageBarPointsRuleDetail(queryParam);
        if (!oldDetailList.isEmpty()) {
            List<String> idList = oldDetailList.stream().map(BarPointsRuleDetail::getId).collect(Collectors.toList());
            barPointsRuleDetailDao.deleteBatchIds(idList);
        }
        if (detailList.isEmpty()) {
            return;
        }
        List<BarPointsRuleDetail> newDetailList = new ArrayList<>(detailList.size());
        for (BarPointsRuleDetail detail : detailList) {
            detail.setId(SnowFlake.nextIdStr());
            newDetailList.add(detail);
        }
        barPointsRuleDetailDao.insertBatch(newDetailList);
    }

    @Override
    public BarPointsRuleDetail getCurrentEffectiveRule(int business) {
        Map<Object, Object> ruleMap = redisUtils.getPointsRulesCache();
        BarPointsRuleDetail detailInfo = null;
        if (ObjectUtils.isEmpty(ruleMap)) {
            String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
            BarPointsRule rule = barPointsRuleDao.getCurrentEffectiveRule(currentTime);
            if (ObjectUtils.isEmpty(rule)) {
                return null;
            }
            Map<String, Object> queryParam = new HashMap<>();
            queryParam.put("ruleId", rule.getId());
            queryParam.put("startNum", 0);
            queryParam.put("pageSize", 100);
            List<BarPointsRuleDetail> detailList = barPointsRuleDetailDao.pageBarPointsRuleDetail(queryParam);
            Map<String, Object> ruleDataMap = new HashMap<>();
            for (BarPointsRuleDetail detail : detailList) {
                ruleDataMap.put(String.valueOf(detail.getSourceType()), detail);
                if (detail.getSourceType() == business) {
                    detailInfo = detail;
                }
            }
            redisUtils.setPointsRulesCache(ruleDataMap);
            return detailInfo;
        }
        if (ruleMap.containsKey(String.valueOf(business))) {
            if (ruleMap.get(String.valueOf(business)) instanceof String) {
                return JSON.parseObject((String) ruleMap.get(String.valueOf(business)),BarPointsRuleDetail.class);
            }
        }
        return null;
    }

    /**
     * 数据补全转换
     *
     * @param originList 原始数据列表
     * @param startNum   起始查询数
     * @return 补全数据
     */
    private List<Map<String, Object>> completeResult(List<BarPointsRule> originList, int startNum) {
        if (ObjectUtils.isEmpty(originList)) {
            return new ArrayList<>();
        }
        List<Map<String, Object>> resultList = new ArrayList<>(originList.size());
        int sort = startNum + 1;
        for (BarPointsRule record : originList) {
            Map<String, Object> map = ObjectUtils.object2Map(record);
            map.put("sort", sort);
            resultList.add(map);
            sort++;
        }
        return resultList;
    }
}
